#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "app_console.h"
#include "app_storage.h"
#include "app_thread.h"
#include "app_button.h"
#include "app_ui.h"
#include "app_ble.h"
#include "app_wifi.h"
#include "app_sensor.h"
#include "app_cloud.h"


const static char *TAG = "Thread";
QueueHandle_t AppThread::messageQueue = 0;


static AppThread threadObj;
static AppButton buttonObj;

TaskHandle_t AppThread::taskHandle = NULL;
TimerHandle_t AppThread::timerHandle = NULL;


void SleepFSM::run(void *arg)
{
   MessageHandle *mt = (MessageHandle *)arg;
}


void SleepFSM::enter()
{
   ESP_LOGI(TAG,"enter sleep mode!");
}

void SleepFSM::exit()
{
   ESP_LOGI(TAG,"exit sleep mode!");
}


void NormalFSM::run(void *arg)
{
   MessageHandle *mt = (MessageHandle *)arg;

   MessageHandle mode_m;

   mode_m.type = MessageType::RUN_MODE;
   mode_m.message.mode.mode = RunMode::SLEEP_MODE;
   AppThread::sendMessage(&mode_m);
}

void NormalFSM::enter()
{
   //connect the wifi
   wifiObj->wifiConnect();
   ESP_LOGI(TAG,"enter normal mode!");
}

void NormalFSM::exit()
{
    ESP_LOGI(TAG,"exit normal mode!");
}



int AppThread::sendMessage(MessageHandle *m)
{
   
   if(AppThread::messageQueue)
   {
       if(pdPASS ==xQueueSend(AppThread::messageQueue, ( void * ) m, ( TickType_t ) 0 ))
       {
          return 0x0;
       }
   }

   ESP_LOGW(TAG,"Queue Full!");
 
   return 0xff;
}


AppThread::AppThread()
{
    this->mode = RunMode::MODE_MAX;
    AppThread::messageQueue = xQueueCreate(MAIN_QUEUE_SIZE, sizeof(MessageHandle));
}

void AppThread::create_thread()
{
     AppUI::threadCreate();
     AppWIFI::threadCreate();
     AppBLE::threadCreate();
     AppSensor::threadCreate();
     AppCloud::threadCreate();
}

void AppThread::init()
{
   uint32_t runcnt=0;
   //bsp initialized
   AppStorage::init();
   AppStorage::get(cfgPartitionData::runcnt,runcnt);
   runcnt++;
   AppStorage::set(cfgPartitionData::runcnt,runcnt);
   ESP_LOGI(TAG, "SYSTEM BOOT COUNT IS [%d]",runcnt);
   pwm_init();
   gpio_init();
   adc_init();
   touch_sensor_init();
   i2c_init();
   uart_init(115200,100);
   hal_sd_spi_init();
   hal_dis_spi_init();

   /* Register commands ...*/
   esp_console_register_help_command();
   AppConsole::cmd_register();
   console_init();
}


void AppThread::setmode(RunMode mode)
{
   this->mode = mode;
   switch(mode)
   {
      case RunMode::RUN_MODE:
         this->fsm = dynamic_cast <AppFSM *>(&(this->normal));
      break;

      case RunMode::SLEEP_MODE:
         this->fsm = dynamic_cast <AppFSM *>(&(this->sleep));
      break;

      default:
      break;
   }
}


void AppThread::modeJump(RunMode mode)
{
   if((mode != this->mode) && (mode < RunMode::MODE_MAX))
   {
      if(this->fsm)
      {
         this->fsm->exit();
      }
      //enter new mode
      this->setmode(mode);
      this->fsm->enter();
   }
}


void AppThread::loadConfig(void)
{
   if(sdgetStatus())
   {

   }
}

void AppThread::process()
{
   MessageHandle *mt = 0;
   if( xQueueReceive( AppThread::messageQueue,
                         &(this->message),
                         ( TickType_t ) 5 ) == pdPASS )
   {
      switch(this->message.type)
      {
         case MessageType::RUN_MODE:
            this->modeJump(this->message.message.mode.mode);
         break;

         case MessageType::BUTTON:
         {
            ESP_LOGI(TAG, "Button evt[%d]->[%d]",this->message.message.button.button,this->message.message.button.status); 
            switch(this->message.message.button.button)
            {
               case ButtonNum::UP :
               {
                  switch(this->message.message.button.status)
                  {
                     case ButtonStatus::SHORT :
                        oledMessage_Button(UI_BUTTON_NUM_UP);
                     break;

                     case ButtonStatus::LONG :
                        oledMessage_Button(UI_BUTTON_NUM_ENTER);
                     break;

                     case ButtonStatus::CONTINUE :
                     break;
                  }
                  break;
               }


               case ButtonNum::DOWN :
               {
                  switch(this->message.message.button.status)
                  {
                     case ButtonStatus::SHORT :
                        oledMessage_Button(UI_BUTTON_NUM_DOWN);
                     break;

                     case ButtonStatus::LONG :
                        oledMessage_Button(UI_BUTTON_NUM_EXIT);
                     break;

                     case ButtonStatus::CONTINUE :
                     break;
                  }
                  break;
               }

               case ButtonNum::TOUCH :
               {
                  switch(this->message.message.button.status)
                  {
                     case ButtonStatus::SHORT :
                        oledMessage_Button(UI_BUTTON_NUM_HOME);
                     break;

                     case ButtonStatus::LONG :
                        oledMessage_Button(UI_BUTTON_NUM_SLEEP);
                     break;
                     case ButtonStatus::CONTINUE :
                     break;
                  }
                  break;
               }
            }
            
         } 
         break;

         default:
            mt =  &(this->message);
         break;
      }
   }

   this->fsm->run(mt);

   //check the sd card status
   sd_check();
   vTaskDelay(2); 
    
}


void AppThread::threadtimeCallback(TimerHandle_t handle)
{
   //button process
   buttonObj.run(MAIN_TASK_TIME);
}

void AppThread::thread(void *a)
{
   
   threadObj.init();
   threadObj.create_thread();
   threadObj.modeJump(RunMode::RUN_MODE);
   AppThread::timerHandle = xTimerCreate(TAG, pdMS_TO_TICKS(MAIN_TASK_TIME), true, NULL, AppThread::threadtimeCallback);
   xTimerStart(AppThread::timerHandle,pdMS_TO_TICKS(MAIN_TASK_TIME));
   while(1)
   {
      
      threadObj.process();
   }
}


void AppThread::threadCreate()
{
   xTaskCreate(AppThread::thread, TAG, MAIN_STACK_SIZE, NULL, MAIN_TASK_PRIO, &(AppThread::taskHandle));
}

